<?php
namespace App\Http\Controllers\Payment;

use App\Http\Controllers\Controller;
use App\Jobs\ClosePaymentJob;
use App\Jobs\PushMsgJob;
use App\Jobs\SendSystemMsgJob;
use App\Libraries\Tools\ConstVar;
use App\Libraries\Tools\Msg;
use App\Libraries\Tools\Tools;
use App\Models\HongBao\HongBao;
use App\Models\Order\Order;
use App\Models\Post\Post;
use App\Models\Post\PostPurchase;
use App\Models\Product\Product;
use App\Models\Product\ProductPurchase;
use App\Models\Shop\Shop;
use App\Models\Shop\ShopCoupon;
use App\Models\Shop\ShopCouponPurchase;
use App\Models\Shop\ShopManager;
use App\Models\User\Address;
use App\Models\User\Balance;
use App\Models\User\User;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;


class IOSController extends Controller{

    protected $order;
    protected $post;
    protected $postPurchase;
    protected $auth_user;
    protected $address;
    protected $product;
    protected $productPurchase;
    protected $user;
    protected $balance;
	protected $shopCoupon;
	protected $shopCouponPurchase;

    private $sandbox_url = 'https://sandbox.itunes.apple.com/verifyReceipt';
    private $real_url = 'https://buy.itunes.apple.com/verifyReceipt';
    private $sandbox_user = [
        'nowfc@chuznet.com',
        'niu@chuznet.com',
        'chuznet@chuznet.com',
        'asuray@qq.com',
        'wenqi@chuznet.com',
    ];

    public function __construct(Order $order, Post $post, User $user,
								ShopCoupon $shopCoupon, ShopCouponPurchase $shopCouponPurchase,
								PostPurchase $postPurchase, Address $address,
                                Product $product, ProductPurchase $productPurchase,
                                Balance $balance){
        $this->order = $order;
        $this->post = $post;
        $this->postPurchase = $postPurchase;
        $this->auth_user = Auth::user();
        $this->address = $address;
        $this->product = $product;
        $this->productPurchase = $productPurchase;
        $this->user = $user;
        $this->balance = $balance;
		$this->shopCoupon = $shopCoupon;
		$this->shopCouponPurchase = $shopCouponPurchase;
    }

    /**
     * 生成订单信息
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function orderInfo(Request $request){
        $validator = Validator::make($request->all(), [
            'id' => 'required|integer',
            'type' => 'required|in:1,2,3,4,5,6',//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
            'address_id' => 'integer',
            'quantity' => 'integer',
            'hong_bao_id' => 'integer',
            'transfer_amount' => 'numeric|required_if:type,3,5,6',
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
            'address_id.integer' => '10002',
            'quantity.integer' => '10002',
            'hong_bao_id.integer' => '10002',
            'transfer_amount.numeric' => '10002',
            'transfer_amount.required_if' => '10001',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        switch($request['type']){//1-post 2-product 3-transfer 4-coupon
            case 1:
                $model = $this->post;
                $model_ext = $this->postPurchase;
                break;
            case 2:
                $model = $this->product;
                $model_ext = $this->address;
                break;
            case 3:
                $model = new User();
                $model_ext = new Shop();
                break;
			case 4:
                return $this->sendFailResponse(400, 50001);
				break;
            default:
                return $this->sendFailResponse(400, 50001);
        }

        $rs = $this->order->logic($request, $this->auth_user, ConstVar::$ORDER_CHANNEL_IOS, $model, $model_ext);
        if($rs['code'] != 200){
            return $this->sendFailResponse(400, $rs['code']);
        }

        $job = (new ClosePaymentJob($rs['data']['out_trade_no']))->delay(Carbon::now()->addMinutes(ConstVar::$PAYMENT_CLOSE_DELAY));
        dispatch($job);

        return $this->sendSuccessResponse(['order_info'=>Tools::authcode($rs['data']['out_trade_no'], '', 'ENCODE')]);
    }

    /**
     * IOS回调
     * @param Request $request
     * @return string
     */
    public function notify(Request $request){
        $validator = Validator::make($request->all(), [
            'order_info' => 'required|string',
            'apple_receipt' => 'required|string',//1-post 2-product 3-transfer
        ], [
            'order_info.required' => '10001',
            'order_info.string' => '10002',
            'apple_receipt.required' => '10001',
            'apple_receipt.string' => '10002',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        $order_info = Tools::authcode($request['order_info']);
        $order_info = explode('_', $order_info);
        if(empty($order_info[0]) || empty($order_info[1]) || empty($order_info[2])){
            return $this->sendFailResponse(400, 40001);
        }
        $apple_receipt = str_replace(' ', '+', $request['apple_receipt']);
        $verify_url = $this->real_url;
//        if(in_array($request['apple_user'], $this->sandbox_user)){
//            $verify_url = $this->sandbox_url;
//        }
        $params = json_encode(['receipt-data' => $apple_receipt]);
        $response = Tools::postCurl($verify_url, $params);
        $response = json_decode($response, true);

        if($response['status'] != 0){//真实不行跑沙盒
            $verify_url = $this->sandbox_url;
            $response = Tools::postCurl($verify_url, $params);
            $response = json_decode($response, true);
        }
        if($response['status'] != 0){
            return $this->sendFailResponse(400, 40001);
        }
        $transaction_id = $response['receipt']['in_app'][0]['transaction_id'];
        DB::beginTransaction();
        try{
            $order = $this->order->where('id', $order_info[0])->firstOrFail();
            if(empty($order->status)){//0-待支付 1-成功 2-失败 3-退款
                $order->status = ConstVar::$ORDER_STATUS_SUCCESS;
                if($verify_url == $this->sandbox_url){
                    $order->status = ConstVar::$ORDER_STATUS_TEST;
                }
            }else{
                return $this->sendSuccessResponse([]);
            }
            $order->sid = $transaction_id;
            $order->receipt_amount = $order->total_amount;
            $order->save();

            switch($order_info[1]){//1-post 2-product 3-transfer
                case 1:
                    $postPurchase = $this->postPurchase->where('order_id',$order_info[0])->first();
                    $postPurchase->status=1;
                    $postPurchase->save();
                    $purchase_id = $postPurchase->id;
                    $this->balance->add(
                        Msg::IOS_consumption().'_'.Msg::balance_post_profit($order_info[2]),
                        $order->user_id,
                        $order_info[3],
                        ConstVar::$BALANCE_CHANNEL_IOS,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_POST,
                        $order_info[2],
                        $order->total_amount,
                        $purchase_id
                    );
//                    $this->user->where('user_id', $order_info[3])->increment('balance', $order->total_amount);
                    break;
                case 2:
                    $productPurchase = $this->productPurchase->where('order_id',$order_info[0])->first();
                    $productPurchase->status=1;
                    $productPurchase->save();
                    $purchase_id = $productPurchase->id;
                    $this->balance->add(//消费记录
                        Msg::IOS_consumption().'_'.Msg::balance_product_profit($order_info[2]),
                        $order->user_id,
                        0,
                        ConstVar::$BALANCE_CHANNEL_IOS,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_PRODUCT,
                        $order_info[2],
                        $order->receipt_amount,
                        $purchase_id,
                        $order->hong_bao_id,
                        $order->hong_bao_amount,
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SYSTEM
                    );
                    $product = Product::find($productPurchase->product_id);
                    if($product->category == 2){
//                      todo      dispatch(new MLMJob($user_id, $channel, $product_id, $this->id));
                        (new User)->addVIP($order->user_id, $product->level, $product->validity);
                    }
                    break;
                case 3:
                    Shop::where('shop_id', $order_info[2])->increment('balance', $order->total_amount);
                    $owner = ShopManager::where('shop_id', $order_info[2])
                        ->where('status', 1)->where('level', 1)->first();
                    $this->balance->add(//transfer记录
                        Msg::IOS_consumption().'_'.Msg::balance_transfer_profit(),
                        $order->user_id,
                        $order_info[2],
                        ConstVar::$BALANCE_CHANNEL_IOS,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP,
                        $order_info[2],
                        $order->total_amount,
                        0,
                        $order->hong_bao_id,
                        $order->hong_bao_amount,
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SHOP
                    );
                    if(!empty($owner)){
                        dispatch(new SendSystemMsgJob([$owner->user_id], Msg::transfer_to_shop($order->total_amount), 0));
                        dispatch(new PushMsgJob([$owner->user_id], Msg::transfer_to_shop($order->total_amount), 0));
                    }
                    break;
				case 4:
                    $shopCouponPurchase = $this->shopCouponPurchase->where('order_id',$order_info[0])->first();
                    $shopCouponPurchase->status=0;
                    $shopCouponPurchase->save();
                    $purchase_id = $shopCouponPurchase->id;
                    $this->balance->add(//消费记录
                        Msg::IOS_consumption().'_'.Msg::balance_coupon_profit($order_info[2]),
                        $order->user_id,//from_id
                        0,
                        ConstVar::$BALANCE_CHANNEL_IOS,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_COUPON,
                        $order_info[2],//coupon_id
                        $order->receipt_amount,
                        $purchase_id,
                        $order->hong_bao_id,
                        $order->hong_bao_amount,
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SYSTEM
                    );
					break;
                default:
                    DB::rollBack();
                    return $this->sendFailResponse(400, 50001);
                    break;
            }
        }catch (\Exception $e){
            DB::rollBack();
            Log::critical('IOS fail', $request->all());
            Log::critical('IOS fail', ['msg'=>$e->getTraceAsString()]);
            return $this->sendFailResponse(500, 50000);
        }
        DB::commit();
        return $this->sendSuccessResponse([]);
    }
}